package dimension.starry.block.typeInterface;

import dimension.starry.block.machine.industry.steamer.SteamTileEntity;
import dimension.starry.item.ItemRegisterManager;
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory;
import net.fabricmc.fabric.api.screenhandler.v1.FabricScreenHandlerFactory;
import net.minecraft.block.AbstractFurnaceBlock;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.AbstractFurnaceBlockEntity;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityTicker;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.inventory.Inventory;
import net.minecraft.inventory.SimpleInventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.screen.NamedScreenHandlerFactory;
import net.minecraft.screen.PropertyDelegate;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;

public abstract class MachineTileEntity extends BlockEntity implements ExtendedScreenHandlerFactory {

    private static final String STORE_ITEM_KEY = "item";
    private static final int PROGRESS_INDEX = 0;
    private static final int MACHINE_STATUS_INDEX = 1;
    private static final int FUEL_INDEX = 2;

    protected final SimpleInventory inventory;
    private final ContainerProgress containerProgress;
    private final Text labelText;
    private final int consumeTime;
    private BlockPos steamerPos;
    private long lastSearchSteamTime;

    public MachineTileEntity(
        BlockEntityType<?> type, BlockPos pos, BlockState state, int inventorySize, Text labelText, int consumeTime
    ) {
        super(type, pos, state);
        this.inventory = new SimpleInventory(inventorySize);
        this.containerProgress = new ContainerProgress();
        this.labelText = labelText;
        this.consumeTime = consumeTime;
    }

    protected static int getFuelAddCount(Item fuel) {
        if (fuel.equals(Items.COAL)) {
            return 1000;
        } else if (fuel.equals(ItemRegisterManager.ANTHRACITE.getItem())) {
            return 1600;
        }
        return 0;
    }

    @Override
    public Text getDisplayName() {
        return labelText;
    }

    @Override
    public void readNbt(NbtCompound nbt) {
        super.readNbt(nbt);
        if (!hasWorld()) {
            for (int i = 0; i < inventory.size(); i++) {
                this.inventory.setStack(i, ItemStack.fromNbt(nbt.getCompound(STORE_ITEM_KEY + i)));
            }
        }
    }

    @Override
    public void writeNbt(NbtCompound nbtCompound) {
        super.writeNbt(nbtCompound);
        for (int i = 0; i < this.inventory.size(); i++) {
            ItemStack itemStack = this.inventory.getStack(i).copy();
            nbtCompound.put(STORE_ITEM_KEY + i, itemStack.writeNbt(new NbtCompound()));
        }
    }

    public abstract void tick(World world1, BlockPos pos, BlockState state1, MachineTileEntity blockEntity);

    public int getConsumeTime() {
        return this.consumeTime;
    }

    public int getProgress() {
        return this.containerProgress.get(PROGRESS_INDEX);
    }

    public void resetProgress() {
        if (getProgress() != 0) {
            this.containerProgress.set(PROGRESS_INDEX, 0);
            this.markDirty();
        }
    }

    public int getFuel() {
        return this.containerProgress.get(FUEL_INDEX);
    }

    public boolean consumeFuel() {
        int fuel = this.containerProgress.get(FUEL_INDEX);
        if (fuel > 0) {
            this.containerProgress.set(FUEL_INDEX, fuel - 1);
            this.addProgress();
            this.markDirty();
            return true;
        }
        this.setMachineStatus(false);
        return false;
    }

    public void addProgress() {
        this.containerProgress.set(PROGRESS_INDEX, this.getProgress() + 1);
        this.setMachineStatus(true);
        this.markDirty();
    }

    public void addFuel(int count) {
        this.containerProgress.set(FUEL_INDEX, getFuel() + count);
        this.markDirty();
    }

    public ContainerProgress getContainerProgress() {
        return this.containerProgress;
    }

    public boolean getMachineStatus() {
        return this.containerProgress.get(MACHINE_STATUS_INDEX) == 1;
    }

    public void setMachineStatus(boolean isWork) {
        if (getMachineStatus() == isWork) {
            return;
        }
        if (isWork) {
            this.containerProgress.set(MACHINE_STATUS_INDEX, 1);
        } else {
            this.containerProgress.set(MACHINE_STATUS_INDEX, 0);
        }
        this.markDirty();
        this.world.setBlockState(
            this.pos, this.world.getBlockState(this.pos).with(AbstractFurnaceBlock.LIT, isWork), 3);
    }

    public SimpleInventory getInventory() {
        return this.inventory;
    }

    @Override
    public void writeScreenOpeningData(
        ServerPlayerEntity player, PacketByteBuf buf
    ) {
        buf.writeBlockPos(pos);
    }

    public static class ContainerProgress implements PropertyDelegate {

        int[] progress = new int[10];

        @Override
        public int get(int index) {
            return progress[index];
        }

        @Override
        public void set(int index, int value) {
            progress[index] = value;
        }

        @Override
        public int size() {
            return progress.length;
        }
    }

    public boolean hasSteam() {
        if (this.getWorld() == null || this.getWorld().isClient()) {
            return false;
        } else if (steamerPos != null) {
            BlockEntity blockEntity = this.getWorld().getBlockEntity(steamerPos);
            if (blockEntity instanceof SteamTileEntity steamTileEntity && steamTileEntity.getMachineStatus()) {
                return true;
            }
        } else if (System.currentTimeMillis() - lastSearchSteamTime < 3000) {
            return false;
        }
        lastSearchSteamTime = System.currentTimeMillis();
        for (int x = this.getPos().getX() - 5; x < this.getPos().getX() + 5; x++) {
            for (int y = this.getPos().getY() - 5; y < this.getPos().getY() + 5; y++) {
                for (int z = this.getPos().getZ() - 5; z < this.getPos().getZ() + 5; z++) {
                    BlockEntity blockEntity = this.getWorld().getBlockEntity(new BlockPos(x, y, z));
                    if (blockEntity instanceof SteamTileEntity steamTileEntity && steamTileEntity.getMachineStatus()) {
                        steamerPos = new BlockPos(x, y, z);
                        return true;
                    }
                }
            }
        }
        return false;
    }

}
